package arm_search_3.transform.email;

import arm_search_3.crawling.email.EmailCrawler;
import arm_search_3.data.Document;
import arm_search_3.data.Term;
import arm_search_3.data.email.EmailStatistic;
import java.util.ArrayList;
import java.util.HashMap;
import arm_search_3.transform.Parser;

/**
 * EmailParser bertugas mengekstrak isi file email dan mengembalikan koleksi
 * term yang diekstrak
 * @author Robert Gunawan
 */
public class EmailParser implements Parser {

    private EmailCrawler crawlerRef;

    public EmailParser(EmailCrawler crawler) {
        this.crawlerRef = crawler;
    }

    /**
     * mengembalikan true jika line mengandung label
     * @param line string line
     * @return apakah line mengandung label
     */
    private boolean isContainsLabel(String line) {
        try {
            String[] words = line.split("\\s+");
            return words[0].charAt(words[0].length() - 1) == ':';
        } catch (Exception ex) {
            return false;
        }
    }

    /**
     * mengembalikan true jika line mengandung header yang dibutuhkan 
     * @param line string line
     * @return apakah line mengandung header yang dibutuhkan 
     */
    private String isContainsNeededHeader(String line) {
        if (line.contains("xfrom:")) {
            return "xfrom";
        } else if (line.contains("from:")) {
            return "from";
        } else if (line.contains("xto:")) {
            return "xto";
        } else if (line.contains("to:")) {
            return "to";
        } else if (line.contains("subject:")) {
            return "subject";
        } else if (line.contains("date:")) {
            return "date";
        }
        return "";
    }

    /**
     * memproses term
     * @param termSet koleksi term
     * @param term term yang diproses
     * @param label label header
     * @param tokenCounter token counter
     */
    private void ProcessTerm(HashMap<String, Term> termSet, String term, String label, Integer termPos, Integer mapDocID) {
        Term termObject = new Term(term);
        if (!term.equals("")) {
            if (termSet.containsKey(term)) {
                Term existingTerm = (Term) termSet.get(term);
                if (label.equals("xfrom") || label.equals("from")) {
                    ((EmailStatistic) existingTerm.getStatistic()).getDocStatistic(EmailStatistic.from).addPos(mapDocID, termPos);
                } else if (label.equals("xto") || label.equals("to")) {
                    ((EmailStatistic) existingTerm.getStatistic()).getDocStatistic(EmailStatistic.to).addPos(mapDocID, termPos);
                } else if (label.equals("subject")) {
                    ((EmailStatistic) existingTerm.getStatistic()).getDocStatistic(EmailStatistic.subject).addPos(mapDocID, termPos);
                } else if (label.equals("date")) {
                    ((EmailStatistic) existingTerm.getStatistic()).getDocStatistic(EmailStatistic.date).addPos(mapDocID, termPos);
                } else if (label.equals("body")) {
                    ((EmailStatistic) existingTerm.getStatistic()).getDocStatistic(EmailStatistic.body).addPos(mapDocID, termPos);
                }
                ((EmailStatistic) existingTerm.getStatistic()).postCheck();
            } else {
                EmailStatistic stat = new EmailStatistic(termObject.getTermString());
                if (label.equals("xfrom") || label.equals("from")) {
                    stat.getDocStatistic(EmailStatistic.from).addPos(mapDocID, termPos);
                } else if (label.equals("xto") || label.equals("to")) {
                    stat.getDocStatistic(EmailStatistic.to).addPos(mapDocID, termPos);
                } else if (label.equals("subject")) {
                    stat.getDocStatistic(EmailStatistic.subject).addPos(mapDocID, termPos);
                } else if (label.equals("date")) {
                    stat.getDocStatistic(EmailStatistic.date).addPos(mapDocID, termPos);
                } else if (label.equals("body")) {
                    stat.getDocStatistic(EmailStatistic.body).addPos(mapDocID, termPos);
                }
                stat.postCheck();
                termObject.setStatistic(stat);
                termSet.put(term, termObject);
            }
        }
    }

    @Override
    public HashMap<String, Term> doParse(Document document) {
        // System.out.println("# Parsing : "+document.getID());
        ArrayList<String> content = document.extractContent();
        String emailID = content.get(0).split(" ")[1];
        Integer docMapID = crawlerRef.getNewDocID();
        document.setID(emailID);
        crawlerRef.getDocumentMapping().put(docMapID, emailID);

        // System.out.println("Document map id : " + docMapID + ", email id : " + emailID);

        HashMap<String, Term> result = new HashMap<String, Term>();
        boolean isHeader = true;
        HashMap<String, String> extractedHeaderBody = new HashMap<String, String>();
        String currentLabel = "";
        int iter = 0;
        try {
            // process each line
            for (iter = 0; iter < content.size(); iter++) {
                if (isHeader) {
                    // System.out.println("Header : " + content.get(iter));
                    currentLabel = isContainsNeededHeader(content.get(iter));
                    if (!currentLabel.equals("")) {
                        // iterate lines to create
                        String temp = " " + (content.get(iter)).substring(currentLabel.length());
                        iter++;
                        while (!isContainsLabel(content.get(iter))) {
                            temp += " " + content.get(iter);
                            iter++;
                        }
                        iter--;
                        if (extractedHeaderBody.containsKey(currentLabel)) {
                            extractedHeaderBody.put(currentLabel, (((String) extractedHeaderBody.get(currentLabel)) + temp));
                        } else {
                            extractedHeaderBody.put(currentLabel, temp);
                        }
                    } else if (content.get(iter).contains("xfilename:")) {
                        // read forwad until find an empty string line
                        while (!content.get(iter).equals("")) {
                            iter++;
                        }
                        isHeader = false;
                    }
                } else {
                    String temp = "";
                    currentLabel = "body";
                    while (iter < content.size()) {
                        temp += " " + content.get(iter);
                        iter++;
                    }
                    extractedHeaderBody.put(currentLabel, temp);
                }
            }
            Integer termPos = 0;

            // date
            String label = "date";
            String labelContent = extractedHeaderBody.get(label);
            String terms[] = labelContent.replace(':', ' ').split("\\s+");
            Integer pos;
            for (pos = 0; pos < terms.length; pos++) {
                ProcessTerm(result, terms[pos], label, termPos + pos, docMapID);
            }
            termPos += terms.length;
            // from, xfrom
            label = "from";
            labelContent = extractedHeaderBody.get(label);
            terms = labelContent.replace(':', ' ').split("\\s+");
            for (pos = 0; pos < terms.length; pos++) {
                ProcessTerm(result, terms[pos], label, termPos + pos, docMapID);
            }
            termPos += terms.length;
            label = "xfrom";
            labelContent = extractedHeaderBody.get(label);
            terms = labelContent.replace(':', ' ').split("\\s+");
            for (pos = 0; pos < terms.length; pos++) {
                ProcessTerm(result, terms[pos], label, termPos + pos, docMapID);
            }
            termPos += terms.length;
            // to, xto
            label = "to";
            labelContent = extractedHeaderBody.get(label);
            terms = labelContent.replace(':', ' ').split("\\s+");
            for (pos = 0; pos < terms.length; pos++) {
                ProcessTerm(result, terms[pos], label, termPos + pos, docMapID);
            }
            termPos += terms.length;
            label = "xto";
            labelContent = extractedHeaderBody.get(label);
            terms = labelContent.replace(':', ' ').split("\\s+");
            for (pos = 0; pos < terms.length; pos++) {
                ProcessTerm(result, terms[pos], label, termPos + pos, docMapID);
            }
            termPos += terms.length;
            // subject
            label = "subject";
            labelContent = extractedHeaderBody.get(label);
            terms = labelContent.replace(':', ' ').split("\\s+");
            for (pos = 0; pos < terms.length; pos++) {
                ProcessTerm(result, terms[pos], label, termPos + pos, docMapID);
            }
            termPos += terms.length;
            // body
            label = "body";
            labelContent = extractedHeaderBody.get(label);
            terms = labelContent.replace(':', ' ').split("\\s+");
            for (pos = 0; pos < terms.length; pos++) {
                ProcessTerm(result, terms[pos], label, termPos + pos, docMapID);
            }
            termPos += terms.length;
        } catch (Exception ex) {
            // System.out.println("## error parse line");
        }
        content.clear();
        return result;
    }
}